package com.snlab;

import jdd.bdd.BDD;

import java.math.BigInteger;

public final class BDDEngine {
    public BDD bdd;
    int[] vars;
    public final static int BDDFalse = 0;
    public final static int BDDTrue = 1;
    public int cnt = 0;

    // bdd variable array is from high bit to low bit
    public BDDEngine(int size) {
        this.bdd = new BDD(1000, 1000);
        this.vars = new int[size];
        for (int i = 0; i < size; i++) {
            vars[i] = bdd.createVar();
        }
    }

    public int encodeIpv4(long ip, int prefix) {
        return this.encodeIpv4(BigInteger.valueOf(ip), prefix);
    }

    public int encodeIpv4(BigInteger ip, int prefix) {
        int result = BDDTrue;
        for (int i = 0; i < prefix; i++) {
            if (ip.testBit(31 - i)) {
                int tmp = and(result, vars[i]);
                bdd.deref(result);
                result = tmp;
            } else {
                int tmp = not(vars[i]);
                int tmp1 = and(result, tmp);
                bdd.deref(tmp);
                bdd.deref(result);
                result = tmp1;
            }
        }
        return result;
    }

    public int and(int x, int y) {
        int r = bdd.and(x, y);
        bdd.ref(r);
        cnt++;
        return r;
    }

    public int or(int x, int y) {
        int r = bdd.or(x, y);
        bdd.ref(r);
        cnt++;
        return r;
    }

    public int not(int x) {
        int r = bdd.not(x);
        bdd.ref(r);
        cnt++;
        return r;
    }
}
